package com.apes.framework.jpa.dialect;

import org.hibernate.JDBCException;
import org.hibernate.QueryTimeoutException;
import org.hibernate.dialect.Oracle10gDialect;
import org.hibernate.exception.ConstraintViolationException;
import org.hibernate.exception.LockAcquisitionException;
import org.hibernate.exception.LockTimeoutException;
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
import org.hibernate.internal.util.JdbcExceptionHelper;

import java.sql.SQLException;

/**
 * 功能：
 *
 * @author xul
 * @create 2018-09-26 11:51
 */
public class OracleDialect extends Oracle10gDialect {

    public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
        return new SQLExceptionConversionDelegate() {
            @Override
            public JDBCException convert(SQLException sqlException, String message, String sql) {
                // interpreting Oracle exceptions is much much more precise based on their specific vendor codes.

                final int errorCode = JdbcExceptionHelper.extractErrorCode(sqlException);


                // lock timeouts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                if (errorCode == 30006) {
                    // ORA-30006: resource busy; acquire with WAIT timeout expired
                    throw new LockTimeoutException(message, sqlException, sql);
                } else if (errorCode == 54) {
                    // ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
                    throw new LockTimeoutException(message, sqlException, sql);
                } else if (4021 == errorCode) {
                    // ORA-04021 timeout occurred while waiting to lock object
                    throw new LockTimeoutException(message, sqlException, sql);
                }


                // deadlocks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                if (60 == errorCode) {
                    // ORA-00060: deadlock detected while waiting for resource
                    return new LockAcquisitionException(message, sqlException, sql);
                } else if (4020 == errorCode) {
                    // ORA-04020 deadlock detected while trying to lock object
                    return new LockAcquisitionException(message, sqlException, sql);
                }


                // query cancelled ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                if (1013 == errorCode) {
                    // ORA-01013: user requested cancel of current operation
                    throw new QueryTimeoutException(message, sqlException, sql);
                }


                // data integrity violation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

                if (1407 == errorCode) {
                    // ORA-01407: cannot update column to NULL
                    final String constraintName = getViolatedConstraintNameExtracter().extractConstraintName(sqlException);
                    return new ConstraintViolationException(message, sqlException, sql, constraintName);
                }
                return new JDBCException(sqlException.getMessage(), sqlException, sql);
            }
        };
    }
}
